package com.lucenten.collect.gnss.runnable.impl;

import cn.quevo.common.lang.NumberUtils;
import cn.quevo.common.lang.StringUtils;
import cn.quevo.core.spring.util.PropertiesUtils;
import com.lucenten.collect.config.entity.dto.ThreadStation;
import com.lucenten.collect.config.entity.query.CollectConfQuery;
import com.lucenten.collect.config.service.CollectConfService;
import com.lucenten.collect.gnss.entity.SatelliteStation;
import com.lucenten.collect.gnss.entity.query.SatelliteStationQuery;
import com.lucenten.collect.gnss.handler.tools.GnssContext;
import com.lucenten.collect.gnss.runnable.GnssUnZipRunService;
import com.lucenten.collect.gnss.runnable.GnssUnZipRunnable;
import com.lucenten.collect.gnss.service.SatelliteStationService;
import com.lucenten.collect.utils.FileUtils;
import com.lucenten.mq.SendJmsInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * Gnss采集Service
 *
 * @author July july_sky@foxmail.com
 * @version 1.0
 * @date 2019/4/27 20:20
 * @Copyright 东方浩星（北京）传媒科技有限公司版权所有.All Rights Reserved.
 */
@Slf4j
@Service("gnssUnZipRunService")
public class GnssUnZipRunServiceImpl implements GnssUnZipRunService {
    private final PropertiesUtils props = new PropertiesUtils("/conf/gnss.properties");
    private final String stationCode = props.getProperties("collect.station.code");
    private final Integer THREAD_NUM = NumberUtils.toInt(props.getProperties("collect.station.thread.num", "10"));
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(THREAD_NUM);

    @Resource(name = "collectConfService")
    private CollectConfService collectConfService;
    @Resource(name = "satelliteStationService")
    private SatelliteStationService satelliteStationService;

    private static Integer RUN_INDEX = 0;
    @Override
    public void run(String root) {
        CollectConfQuery query = CollectConfQuery.builder().serverCode(stationCode).build();
        ThreadStation threadStation = collectConfService.getCollectConfByCode(query);
        if (threadStation == null) {
            log.debug(stationCode + " 尚未开启");
            return;
        }
        List<SatelliteStation> stations = this.satelliteStationService.getSatelliteStationList(SatelliteStationQuery.builder().build());
        if (StringUtils.isEmpty(stations)) {
            log.debug(stationCode + " 暂无站点信息");
            return;
        }

        int fileCount = 0;
        Path source = Paths.get(root);
        try {
            fileCount = this.sum(source).intValue();
        } catch (IOException e) {
            log.error("文件遍历失败：", e);
        }
        SendJmsInfo.sendGnssFileQty(fileCount);
        int start = 0;
        int end = threadStation.getStationQty();
        RUN_INDEX = start + 1;
        end = end > fileCount ? fileCount : end;

        this.startThread(source, start, end,stations);
    }

    public void startThread(Path root, int start, int end,List<SatelliteStation> stations) {
//        List<Path> files = new ArrayList<>(end-start);
        Map<String,SatelliteStation> stationMap = new LinkedHashMap<>();
        Map<String,SatelliteStation> reStationMap = new LinkedHashMap<>();
        try {
            this.convertMap(stations, stationMap,reStationMap);
            this.getFiles(root,0L,start, end+start, stationMap,reStationMap);
        } catch (Exception e) {
            log.error("文件遍历失败：", e);
        }
    }

    /**
     * List转Map
     *
     * @param stations
     * @param stationMap
     */
    private void convertMap(List<SatelliteStation> stations, Map<String,SatelliteStation> stationMap,Map<String,SatelliteStation> reStationMap) {
        for (SatelliteStation satelliteStation : stations) {
            stationMap.put(satelliteStation.getStationId()+","+satelliteStation.getStationName(), satelliteStation);
            reStationMap.put(satelliteStation.getReStationName(), satelliteStation);
        }
    }

    /**
     * 获取总文件个数
     *
     * @param root
     * @return
     * @throws IOException
     */
    private Long sum(Path root) throws IOException {
        long count = Files.list(root).filter(dire -> !Files.isDirectory(dire) && GnssContext.isZipExt(dire.getFileName().normalize().toString())).count();
        List<Path> list = Files.list(root).filter(dire -> Files.isDirectory(dire)).collect(Collectors.toList());
        if (StringUtils.isEmpty(list)) {
            return count;
        }
        for (Path p : list) {
            count += sum(p);
        }
        return count;
    }

    /**
     * 获取总文件个数
     *
     * @param root
     * @return
     * @throws IOException
     */
    private Long getFiles(Path root,long count,int begin,int end,List<Path> fileList) throws IOException {
        if (count >= end) {
            return count;
        }
        long qty = Files.list(root).filter(dire -> !Files.isDirectory(dire) && GnssContext.isZipExt(dire.getFileName().normalize().toString())).count();
        count += qty;

        if (count > begin) {
            long skip = count - begin >= qty ? 0 : qty - (count - begin);
            long limit = end - begin;
            limit = limit > qty - skip ? qty - skip : limit;
            fileList.addAll(Files.list(root).filter(dire -> !Files.isDirectory(dire) && GnssContext.isZipExt(dire.getFileName().normalize().toString())).skip(skip).limit(limit).collect(Collectors.toList()));
        }
        List<Path> list = Files.list(root).filter(dire -> Files.isDirectory(dire)).collect(Collectors.toList());
        if (StringUtils.isEmpty(list)) {
            return count;
        }
        for (Path p : list) {
            count = getFiles(p,count, begin, end,fileList);
        }
        return count;
    }
    /**
     * 获取总文件个数
     *
     * @param root
     * @return
     * @throws IOException
     */
    private Long getFiles(Path root,long count,int begin,int end,Map<String,SatelliteStation> stationMap,Map<String,SatelliteStation> reStationMap) throws IOException {
        if (count >= end) {
            return count;
        }
        long qty = Files.list(root).filter(dire -> !Files.isDirectory(dire) && GnssContext.isZipExt(dire.getFileName().normalize().toString())).count();
        count += qty;

        if (count > begin) {
            long skip = count - begin >= qty ? 0 : qty - (count - begin);
            long limit = end - begin;
            limit = limit > qty - skip ? qty - skip : limit;
            Files.list(root).filter(dire -> !Files.isDirectory(dire) && GnssContext.isZipExt(dire.getFileName().normalize().toString())).skip(skip).limit(limit).forEach(file -> {
                GnssUnZipRunnable runnable = GnssUnZipRunnable.builder().index(RUN_INDEX ++).root(root).file(file).stationMap(stationMap).reStationMap(reStationMap).build();
                fixedThreadPool.execute(runnable);
            });
        }
        List<Path> list = Files.list(root).filter(dire -> Files.isDirectory(dire)).collect(Collectors.toList());
        if (StringUtils.isEmpty(list)) {
            return count;
        }
        for (Path p : list) {
            count = getFiles(p,count, begin, end,stationMap,reStationMap);
        }
        return count;
    }
}
